// Sifteo Scramble
// Kyler Connare
// Cameron Burton
// Brandon Walruth
// Zachary Berhmann
//

#include <sifteo.h>
#include <sifteo/menu.h>
#include <sifteo/asset/image.h>
#include "assets.gen.h"

using namespace Sifteo;

static 			int				numCubes = 3; // default 3
static const    int				maxGameCubes = 12;
static			Neighborhood	neighbors;
static			int				cooldown = 3;
static			float			timeReduction = 0;

static AssetSlot MainSlot = AssetSlot::allocate()
	.bootstrap(GameAssets);

static Metadata M = Metadata()
	.title("Sifteo Scramble")
	.package("edu.rit.khc7158.tilting", "0.1")
	.icon(Icon)
	.cubeRange(3,12);


	
// Enums?
enum { SHAKE, SLANT, STRIKE };
/*
Scramble.png
Shake.png
Slam.png
Slant.png
Slide.png
Spin.png
Strike.png
Swap.png
*/


class ScrambleCube {
public:
//INB4 getters and setters:
bool active;	//Is the cube active
//float cooldown; //The time til we use the cube again

	void init(CubeID _cube){
		cube = _cube;
		active = false;
		timespan = 0;
		//cooldown = 3;
		vid.initMode(BG0_SPR_BG1);
		vid.attach(cube);
		// Put in the background image
		if(cube % 6 == 0)
			cubeImage = BlueCube;
		else if(cube % 6 == 1)
			cubeImage = GreenCube;
		else if(cube % 6 == 2)
			cubeImage = RedCube;
		else if(cube % 6 == 3)
			cubeImage = OrangeCube;
		else if(cube % 6 == 4)
			cubeImage = PurpleCube;
		else if(cube % 6 == 5)
			cubeImage = CyanCube;
		vid.bg0.image(vec(0,0), cubeImage, 0);
		motion.attach(cube);
	}

	int update(TimeDelta timestep){
		timespan += timestep.seconds();
		if(active){
			motion.update();
			if(timespan >= 5.0 - timeReduction){
				return -1;
			}
			else{
				return checkAction(); //yay in C++ F/T = 0/1 respectively
			}
		}
		else
		//If we aren't active, lower the cooldown
		{
			//cooldown -= timestep.seconds();
			return 2;
		}
		//If nothing happens, we want to return am error state I guess
		return -2;
	}
		
	void scrambleStart(int move){ // take a param that sets game num

		LOG("scrambleStart: %d\n", move);
		//writeText("STARTED");
		done = false;
		active = true;
		timespan = 0;
		//cooldown = 0;
		moveName = move;

		//vid.bg1.fillMask( vec(1, 14), vec(14, 1) );
	
		switch (moveName) {
		case SHAKE:
			{
				numShake = 0;
				vid.bg0.image(vec(0,0), Shake);
			} break;
		case SLANT:
			{
				timeTilt = 0;
				vid.bg0.image(vec(0,0), Slant);
			} break;
		case STRIKE:
			{
				touching = false;
				vid.bg0.image(vec(0,0), Strike);
			} break;
		}
	}
	
	void gameOver() {
		vid.bg0.image(vec(0,0), GameOverImage);
	}
	
	
	bool isDone() {
		return done;
	}
	
	bool isActive(){
		return active;
	}
	
	float getTimespan() {
		return timespan;
	}
	
	CubeID &getCubeID() {
		return cube;
	}
	
	//float getCooldown(){
	//	return cooldown;
	//}

private:
	VideoBuffer vid;
	CubeID		cube;
	int			moveName;
	float 		timespan;
	int 		numShake;
	int 		timeTilt;
	bool 		touching;
	bool 		done;
	TiltShakeRecognizer motion;
	AssetImage 	cubeImage;
	
	
	bool checkAction(){
		switch (moveName) {
			case SHAKE:
			{
				/*numShake = 0;
				Float2 accel = vid.physicalAccel().xy();
				if (abs(accel.x) > 30 && abs(accel.y) > 30) {
					//numShake++;
					//if (numShake >= 1) {
						
						LOG("DONE");
						vid.bg0.image(vec(0,0), cubeImage);
						return 1;
					//}
				}*/
				//Not sure if this works reliably yet
				if(motion.shake){
					LOG("SHOOK");
					vid.bg0.image(vec(0,0), cubeImage);
					//writeText("SHOOK!");
					timeReduction += .1;
					return 1;
				}
			}
			break;
			case SLANT:
			{
				auto tilt = motion.tilt;
				if(tilt.x != 0 || tilt.y != 0){
					LOG("SLANTED");
					vid.bg0.image(vec(0,0), cubeImage);
					//writeText("SLANTED!");
					timeReduction += .1;
					return 1;
				}
				/*timeTilt = 0;
				if (abs(vid.physicalAccel().x) > 5 || abs(vid.physicalAccel().y) > 5){
					//timeTilt++;
					//if(timeTilt >= 1){
						vid.bg0.image(vec(0,0), cubeImage);
						writeText("SLANT!");
						return 1;
					//}
				}*/
			}
			break;
			case STRIKE:
			//Simplified the code, unless we have another issue?
			{
				if(cube.isTouching())
				{
					vid.bg0.image(vec(0,0), cubeImage);
					//writeText("TOUCHED!");
					timeReduction += .1;
					return 1;
				}
			}
			break;
		}
		return false;
	}
	
	
 void writeText(const char *str)
    {
        // Text on BG1, in the 16x2 area we allocated
        vid.bg1.text(vec(0,14), Font, str);
    }

};

void main() {
	
	static ScrambleCube cubes[maxGameCubes];
	bool firstRun = true;
	bool dispatch = true;
	bool gameOver = false;
	// Call the initialization function on each cube
	for (int i = 0; i < numCubes; i++)
		cubes[i].init(i);
		
	TimeStep ts;
	Random rand;
	int clearState = 0;
	while (!gameOver) {
	//Only do this on the first run
	//we need a better way of doing this
	//I only supported one cube for testing purposes
	//that and the display getting blurry SUCKS ON THE EMU
		if(firstRun){
			int currentCube = rand.randint(0,numCubes - 1);
			cubes[currentCube].scrambleStart(rand.randint(0,2));
			firstRun = false;
		}
		else{
			cooldown -= ts.delta().seconds();
			for(int i = 0; i < numCubes; i++){
				clearState = cubes[i].update(ts.delta());
				
				if(clearState == 1){
					LOG("DID IT\n");
					//The action was completed, enter cooldown, set inactive
					//for now, cooldown of 3 seconds
					//however, this will have to change in order to
					//deal with audio - we don't want crossover
					//so proper delay will be required/speeding up of sound, etc.
					//in order for cubes not to clash
					cubes[i].active = false;
					//cubes[i].cooldown = 3;
					cooldown = 3;
				}
				else if(clearState == -1){
				//they failed the action, for now, just report that we failed
						LOG("LOST\n");
						cubes[i].active = false;
						//cubes[i].cooldown = 3;
						cooldown = 0;
						gameOver = true;

				}
				else if(clearState == 0){
				//we're waiting for the player to perform
					LOG("WAITING\n");
				}
				else if(clearState == -2){
				//error! WTF?
					LOG("I AM ERROR");
				}
				
			}
			
			dispatch = true;
			for(int i = 0; i < numCubes; i++){
				if(cubes[i].isActive()){
					dispatch = false;
				}
			}
			if(dispatch){
				cubes[rand.randint(0,numCubes - 1)].scrambleStart(rand.randint(0,2));
				cooldown = 3;
				//dispatch = false;
			}
			
			
		}
		
		System::paint();
		ts.next();
	}
	
	for(int i = 0; i < numCubes; i++) {
		cubes[i].gameOver();
		//cubes[i].writeText(score); 
	}
	System::paint();
	while(true) {
		// Tee hee, you must wait for eternity
		System::paint();
		ts.next();
	}
}